package builder

import (
	"fmt"
	"io/ioutil"
	"mi/compiler/ast"
	"mi/compiler/diagnostic"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

const buildGradleFileTmp = `
buildscript {
    repositories {
        maven {
            url 'http://maven.aliyun.com/nexus/content/groups/public/'
        }
        maven {
            url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'
        }
    }
}

plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    id 'java'
}

repositories {
    mavenLocal()
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

dependencies {
    // Use JUnit test framework.
    testImplementation 'junit:junit:4.13.1'

    // This dependency is used by the application.
    // implementation 'com.google.guava:guava:30.0-jre'
}

tasks.withType(JavaCompile) {  
    options.encoding = "UTF-8"  
}

jar {
    manifest {
        attributes 'Main-Class': "${Main-Class}"
    }
} 

task deleTask(type: Delete){  
    FileTree tree = fileTree("build\\classpath")
    tree.each {File file ->
        delete file
    }
}

task copyJars(type:Copy) {
    dependsOn deleTask
    from configurations.runtimeClasspath
    into 'build\\classpath'
}
build.finalizedBy(copyJars)
`
const settingsGradleTmp = `
rootProject.name = '${RootProjectName}'
include('${ProjectName}')
`
const rootProjectName = "project"
const projectName = "project"

func buildProject(project *ast.ProjectFile, run bool) *diagnostic.Diagnostic {
	if len(os.Getenv("JAVA_HOME")) == 0 {
		return diagnostic.CreateCompilerDiagnostic(
			diagnostic.M_Environment_variables_0_are_not_set, "JAVA_HOME")
	}

	if len(os.Getenv("GRADLE_HOME")) == 0 {
		return diagnostic.CreateCompilerDiagnostic(
			diagnostic.M_Environment_variables_0_are_not_set, "GRADLE_HOME")
	}

	// Make gradle project struct
	var dirs = []string{
		filepath.Join(project.OutputPath, projectName, "src", "main", "java"),
		filepath.Join(project.OutputPath, projectName, "src", "main", "resources"),
		filepath.Join(project.OutputPath, projectName, "test", "main", "resources"),
		filepath.Join(project.OutputPath, projectName, "test", "main", "resources"),
	}
	for _, dir := range dirs {
		if diag := makeDirAll(dir, os.ModePerm); diag != nil {
			return diag
		}
	}

	// Write .gitignore
	var err = ioutil.WriteFile(filepath.Join(project.OutputPath, ".gitignore"), nil, os.ModePerm)
	if err != nil {
		return diagnostic.CreateCompilerDiagnostic(
			diagnostic.M_0_error_Colon_1, "writeFile", err.Error())
	}

	// Write settings.gradle file
	var content = strings.ReplaceAll(settingsGradleTmp,"${RootProjectName}", rootProjectName)
	content = strings.ReplaceAll(content,"${ProjectName}", projectName)
	err = ioutil.WriteFile(filepath.Join(project.OutputPath, "settings.gradle"), []byte(content), os.ModePerm)
	if err != nil {
		return diagnostic.CreateCompilerDiagnostic(
			diagnostic.M_0_error_Colon_1, "writeFile", err.Error())
	}

	// Write build.gradle file
	content = strings.ReplaceAll(buildGradleFileTmp,"${Main-Class}", project.MainClass)
	err = ioutil.WriteFile(filepath.Join(project.OutputPath, projectName, "build.gradle"), []byte(content), os.ModePerm)
	if err != nil {
		return diagnostic.CreateCompilerDiagnostic(
			diagnostic.M_0_error_Colon_1, "writeFile", err.Error())
	}

	// Gradle build

	var gradleHome = os.Getenv("GRADLE_HOME")
	var gradlePath = filepath.Join(gradleHome, "bin", "gradle.bat")

	var cmd = exec.Command(gradlePath)
	cmd.Args = append(cmd.Args, "build")
	cmd.Dir = filepath.Join(project.OutputPath)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stdout
	err = cmd.Run()
	if err != nil {
		return diagnostic.CreateCompilerDiagnostic(
			diagnostic.M_Build_error_colon_0, err.Error())
	}

	if run {
		return runProject(project)
	}


	return nil
}

func runProject(project *ast.ProjectFile) *diagnostic.Diagnostic {
	var javaHome = os.Getenv("JAVA_HOME")
	var cmd = exec.Command(filepath.Join(javaHome, "bin", "java.exe"))
	cmd.Args = append(cmd.Args, "-jar")
	cmd.Args = append(cmd.Args, "./输出/project/build/libs/project.jar")
	cmd.Dir = filepath.Dir(project.Uri.Filename())
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stdout
	fmt.Println("开始运行:")
	var err = cmd.Run()
	if err != nil {
		fmt.Errorf(err.Error())
		return diagnostic.CreateCompilerDiagnostic(
			diagnostic.M_error_Colon_0, err.Error())
	}
	return nil
}

func makeDirAll(path string, perm os.FileMode) *diagnostic.Diagnostic {
	var err = os.MkdirAll(path, perm)
	if err != nil {
		return diagnostic.CreateCompilerDiagnostic(
			diagnostic.M_Could_not_make_dir_0_Colon_1, path, err.Error())
	}
	return nil
}